package cn.ljy.mes.service;

import cn.ljy.authority.service.BaseService;
import cn.ljy.mes.model.WmsMaterialBatch;
import cn.ljy.mes.model.WmsMaterialInventoryDetail;
import cn.ljy.mes.model.query.WmsMaterialInventoryDetailQuery;

import javax.validation.constraints.Min;
import javax.validation.constraints.NotNull;

public interface WmsMaterialInventoryDetailService extends BaseService<WmsMaterialInventoryDetail, WmsMaterialInventoryDetailQuery> {
    /**
     * 进行移库操作，同时记录移库日志
     * 说明：
     * 1.源库位与目标库位不能相同
     * 2.如果源库位或目标库位、物料或物料批次为锁定状态，均无法移库。
     * 3.移库时的最大数量=库存数量-锁定数量
     * 4.如果源库位的商品数量在移库后为0并且锁定数量为0，则移除源库位（物料业务中貌似要保存，但是在本系统因为要做太多测试，因此暂时选择移除）
     * 5.如果目标库位原来已经存在该物料，则直接将物料数量（要求同批次）相加；否则新建一个库位详情记录。
     * @param materialInventoryDetailOfSource 源库位信息
     * @param materialInventoryDetailOfTarget 要移动到的目标库位信息，包含要移入的数量。
     */
    void relocation(WmsMaterialInventoryDetail materialInventoryDetailOfSource,WmsMaterialInventoryDetail materialInventoryDetailOfTarget);

    /**
     * 预出库，按物料批次进行预出库操作，不记录出库日志。
     * 预出库的商品在库存中锁定数量，如果之前库存中已经有锁定数量，则预出库后锁定数量增加。
     * 说明：设计是在生产需要使用物料时，如果该生产步骤未审核通过，则物料只是预出库；只有审核通过了才是真正的出库。
     * 1.对某一物料批次执行预出库操作，如果物料批次被锁定或库存不足无法执行预出库。
     * 2.预出库规则
     * （1）已经锁定的库位无法继续预出库，库位锁定数量不计入有效库存（即剩余库存等于库存-锁定数量）
     * （2）如果物料批次有多个库位，则优先从该批次物料少、其次锁定数量多的库位取货（意图先将某一库位清空）
     * （3）如果物料批次有多个库位，并且物料批次少的库位不足以支撑此次出库数量，则从另一个库位（物料批次次少）的库位补充出库，以此类推第三、四个库位。
     * @param materialBatch 一般是供其他类调用，所以该对象应包含除关联字段外的所有基本信息。
     * @param number 出库的数量
     * @param reason 出库的原因
     */
    void reserveForOutboundByMaterialBatch(@NotNull(message = "验证失败：物料批次不能为空") WmsMaterialBatch materialBatch,
                                           @NotNull(message = "验证失败：出库数量不能为空")Long number,
                                           String reason
                                           );

    /**
     * 解决物料批次预出库的最终流向（出库，还是撤销出库）：
     * 如果是出库，则将预出库时锁定的数量转为真正出库（即减少库存），同时记录出库日志；如果是撤销出库，则只减少锁定数量，不减少库存，同时记录锁定数量日志
     * 说明：
     * 1.对某一物料批次执行出库/撤销出库操作，如果物料批次被锁定或库存不足无法执行。
     * 2.出库规则
     * （1）已经锁定的库位无法执行出库/撤销出库操作。
     * （2）如果物料批次只有一个库位，则从库位中的锁定数量中解锁number个数量，如果是出库则要将库存数量要减少number个。
     * （3）如果物料批次有多个库位。
     * 执行出库则优先从该批次有效库存少的库位出库（优先将库位少的物料取空）、执行撤销出库则优先从该批次有效库存多的库位额核销（优先将库位少的物料取空）。
     * 如果一个库位不足以支撑此次出库数量，则从另一个库位的库位补充出库，以此类推第三、四个库位。
     * @param materialBatch 一般是供其他类调用，所以该对象应包含除关联字段外的所有基本信息。
     * @param reservationAction 出库动作，出库或是撤销出库，具体见枚举类型
     * @param number 出库/撤销出库的数量
     * @param reason 出库/撤销出库的原因
     */
    void settleReservationByMaterialBatch(@NotNull(message = "验证失败：物料批次不能为空") WmsMaterialBatch materialBatch,
                                          @NotNull(message = "验证失败：出库动作不能为空") String reservationAction,
                                          @NotNull(message = "验证失败：数量不能为空")@Min(value = 0, message = "数量不能小于0")Long number,
                                          String reason);


    /**
     * 出库操作，按物料批次进行出库操作，同时记录出库日志
     * 说明：
     * 1.对某一物料批次执行出库操作，如果物料批次被锁定或库存不足无法执行出库。
     * 2.出库规则
     * （1）已经锁定的库位无法出库，库位锁定数量不计入有效库存。
     * （2）如果物料批次有多个库位，则优先从该批次物料少的库位取货。
     * （3）如果物料批次有多个库位，并且物料批次少的库位不足以支撑此次出库数量，则从另一个库位（物料批次次少）的库位补充出库，以此类推第三、四个库位。
     * @param materialBatch 一般是供其他类调用，所以该对象应包含除关联字段外的所有基本信息。
     * @param number 出库的数量
     * @param reason 出库的原因
     */
    void outboundByMaterialBatch(@NotNull(message = "验证失败：物料批次不能为空") WmsMaterialBatch materialBatch, @NotNull(message = "验证失败：数量不能为空")@Min(value = 0, message = "数量不能小于0")Long number,String reason);


    /**
     * 入库操作，按物料批次进行入库操作，同时记录入库日志
     * 说明：主要用于生产过程中，因取消生产导致的物料批次回收到仓库。
     * 1.对某一物料批次执行入库操作，如果物料批次被锁定，或是物料仓库的上限已满，则无法执行入库。
     * 2.入库规则
     * （1）已经锁定的库位无法入库。
     * （2）如果物料批次有多个库位，则优先从该批次物料多的库位入库。
     * @param materialBatch 一般是供其他类调用，所以该对象应包含除关联字段外的所有基本信息。
     * @param number 入库的数量
     * @param reason 入库的原因
     */
    void inboundByMaterialBatch(@NotNull(message = "验证失败：物料批次不能为空") WmsMaterialBatch materialBatch, @NotNull(message = "验证失败：数量不能为空") @Min(value = 0, message = "数量不能小于0")Long number, String reason);
}
